C11にもC++(C++11以降)と同じ修飾子(constおよびvolatile)や記憶クラス指定子(extern, static, auto, register, および typedef)が備わっています。ただし、mutable記憶クラス指定子はありません。逆に、C++にはないrestrict修飾子があります。また、微妙に仕様が異なるものがあるため、ここではそれらについて解説します。

const修飾子

const修飾子の振る舞いは、C++とC11ではかなり異なるので注意が必要です。

非局所オブジェクトはデフォルトで外部結合

第2回でも触れましたが、const修飾子の有無にかかわらず、関数の外で宣言した非局所オブジェクトは、明示的にstatic記憶クラス指定子を付けないかぎり外部結合になります。

汎整数定数式にはならない

C++では、const修飾子付きの汎整数型オブジェクトは、列挙定数などと同じように汎整数定数式として扱うことができました。しかし、C11ではそのような例外的な仕様はなく、あくまでも普通のオブジェクトとして振る舞います。したがって、const修飾子付きの汎整数型オブジェクトを、列挙定数の値や、静的な配列の要素、caseラベルの値などに使うことはできません。

restrict修飾子

C11には、C++にはないrestrict修飾子というものがあります。restrict修飾子はポインタしか修飾することができません。restrictで修飾された複数のポインタは、それぞれが同じオブジェクトを指していないこと意味します。つまり、restrict修飾子は、register記憶クラス指定子やinline関数指定子のように、コンパイラに対するヒント情報ということになります。

ところで、C++では、const修飾子とvolatile修飾子をあわせて「cv修飾子」と呼んでいますが、C11はrestrict修飾子を含めて3種類あるため「型修飾子」と呼びます。

_Atomic修飾子

第5回 型と型変換で紹介した_Atomicも修飾子の一種です。ただし、単に「型修飾子」と言った場合は_Atomicを含めないのが普通のようです。<stdatomic.h>をインクルードすることで_Atomicに展開されるatomicマクロを使用することができます。なお、C++11では代わりにatomicクラステンプレートを使用します。

mutable記憶クラス指定子

C11にはmutable記憶クラス指定子はありません。したがって、const修飾子付きで宣言された構造体型のオブジェクトのすべてのメンバは更新することができません。

register記憶クラス指定子

register記憶クラス指定子がヒント情報に過ぎないことは、C11でも同じです。しかし、あくまでもレジスタに割り付けることを前提としていますので、register記憶クラス指定子を付けて宣言したオブジェクトは、&演算子を使ってアドレスを取得することができません。

_Thread_local記憶クラス指定子

第2回 オブジェクトの宣言で紹介した_Thread_localも記憶クラス指定子のひとつです。C++11以降ではthread_localが導入されましたが、C11では_Thread_localというキーワードを使います。<threads.h>をインクルードすれば、_Thread_localに展開されるthread_localマクロを使うこともできます。

typedef記憶クラス指定子

C++では、同じ内容であれば、同一の翻訳単位にtypedefを使った複数の型定義を記述してもエラーになりませんでした。しかし、C11ではそうした記述はエラーになります。


↑ モダンC++プログラマーのためのC11入門